using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace RGuang.Kit
{
    public static class HashKit
    {
        private const int BufferSize = 81920; // 80 KB的缓冲区大小

        #region MD5、SHA-256 说明
        /*
            MD5（Message Digest Algorithm 5）和 SHA-256（Secure Hash Algorithm 256-bit）
            都是广泛使用的哈希函数，但它们在设计、安全性和性能方面存在显著差异。以下是MD5和SHA-256的对比：

            1. 安全性
                    MD5：MD5在1990年代后期被发现存在严重的安全漏洞，包括碰撞攻击和伪随机函数的弱点。
                         因此，MD5不再被认为是安全的，特别是在需要高安全性的场合。

                    SHA-256：SHA-256是SHA-2家族的一部分，设计用于替代MD5和SHA-1。
                         它提供了比MD5更高的安全性，目前还没有发现明显的弱点。
                         SHA-256的256位输出长度使其更难以受到碰撞攻击。
            
            2. 性能
                    MD5：MD5通常比SHA-256更快，因为它的设计更简单，计算更少。
                         然而，这种性能优势在安全性面前变得微不足道。

                    SHA-256：SHA-256的计算复杂度更高，因此它的性能通常低于MD5。
                         但是，对于大多数应用来说，这种差异是可以接受的，特别是考虑到其更高的安全性。

            3. 输出长度
                    MD5：MD5生成一个128位的哈希值，通常表示为32位的十六进制数字。
                    SHA-256：SHA-256生成一个256位的哈希值，通常表示为64位的十六进制数字。

            4. 使用场景
                    MD5：由于MD5的安全性较低，它不再推荐用于需要高安全性的场合，
                         如密码存储、数字签名和敏感数据完整性校验。
                         然而，MD5仍然可以用于一些对安全性要求不高的场合，如文件校验和。

                    SHA-256：SHA-256适用于需要高安全性的场合，
                         如密码哈希、数字签名和敏感数据完整性校验。它是目前推荐的哈希算法之一。

            5. 兼容性
                    MD5：MD5广泛支持，几乎所有编程语言和平台都提供了MD5的实现。

                    SHA-256：SHA-256也得到了广泛的支持，但在一些较旧的系统或库中可能不可用。

            结论
                虽然MD5在某些方面可能比SHA-256更快，但由于其安全性问题，它不再推荐用于需要高安全性的场合。
                SHA-256提供了更高的安全性，尽管它的性能可能略低于MD5。
                在大多数情况下，SHA-256是更优的选择，特别是对于敏感数据的处理。
        */
        #endregion

        /// <summary>
        /// 计算文件的MD5哈希值
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>MD5哈希值</returns>
        public static async Task<string> GetFileHashByMD5(string filePath)
        {
            using (var md5 = MD5.Create())
            {
                using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: BufferSize, useAsync: true))
                {
                    var buffer = new byte[BufferSize];
                    int bytesRead;
                    while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                    {
                        md5.TransformBlock(buffer, 0, bytesRead, null, 0);
                    }
                    md5.TransformFinalBlock(buffer, 0, 0);
                    return BitConverter.ToString(md5.Hash).Replace("-", "").ToLowerInvariant();
                }
            }
        }

        /// <summary>
        /// 计算文件的SHA-256哈希值
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>SHA-256哈希值</returns>
        public static async Task<string> GetFileHashBySHA256(string filePath)
        {
            using (var sha256 = SHA256.Create())
            {
                using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: BufferSize, useAsync: true))
                {
                    var buffer = new byte[BufferSize];
                    int bytesRead;
                    while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                    {
                        sha256.TransformBlock(buffer, 0, bytesRead, null, 0);
                    }
                    sha256.TransformFinalBlock(buffer, 0, 0);
                    return BitConverter.ToString(sha256.Hash).Replace("-", "").ToLowerInvariant();
                }
            }
        }


        /// <summary>
        /// 将哈希值保存到文件
        /// </summary>
        /// <param name="hash">哈希值</param>
        /// <param name="savePath">保存路径</param>
        public static void SaveHashToFile(string hash, string savePath)
        {
            using (var sw = new StreamWriter(savePath, false, Encoding.UTF8))
            {
                sw.Write(hash);
            }
        }

        /// <summary>
        /// 从文件中读取哈希值
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>哈希值</returns>
        public static string ReadHashFromFile(string filePath)
        {
            using (var sr = new StreamReader(filePath, Encoding.UTF8))
            {
                return sr.ReadToEnd();
            }
        }
    }



}


